package com.spring.aop;

import com.spring.aop.interceptor.Interceptor;
import com.spring.aware.ApplicationContextAware;
import com.spring.context.impl.AbstractApplicationContext;
import com.spring.beanpostprocessor.BeanPostProcessor;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
public class AopBeanPostProcessor implements BeanPostProcessor {
	private AbstractApplicationContext ac;
	
	public AopBeanPostProcessor(AbstractApplicationContext ac) {
		this.ac = ac;
	}
	
	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) {
		return wrapIfNecessary(beanName, bean);
	}
	
	/**
	 * 如果有必要，则包装下对象，返回代理
	 */
	public Object wrapIfNecessary(String beanName, Object bean) {
		// 最终需要的 方法 -> 拦截器 Map
		Map<Method, InterceptorChain> interceptorMap = new HashMap<>(16);
		ArrayList<Advisor> advisorList = ac.getAdvisorList();
		Class<?> clazz = bean.getClass();
		
		// 遍历通知信息
		for (Advisor advisor : advisorList) {
			checkAdvisor(interceptorMap, clazz, advisor);
		}
		
		// 没有需要代理的，都是空的, 直接返回原始对象即可
		if (interceptorMap.isEmpty()) {
			return bean;
		}
		
		// 否则创建代理对象
		Object proxy = new CglibProxyCreator().getInstance(bean, interceptorMap);
		log.info("对象 {} 已经被aop代理", beanName);
		return proxy;
	}
	
	/**
	 * 检查通知，是否能匹配这个 bean 的 方法
	 *
	 * 如果有能代理的方法，则往map 中填充数据
	 */
	private void checkAdvisor(Map<Method, InterceptorChain> interceptorMap, Class<?> clazz, Advisor advisor) {
		// 通知不匹配这个bean
		if (!advisor.isMatchBean(clazz)) {
			return;
		}
		// 通知可以匹配这个bean,就检查方法是否有能够匹配的
		Method[] methods = clazz.getMethods();
		for (Method method : methods) {
			if (!advisor.isMatchMethod(method)) {
				continue;
			}
			
			List<Interceptor> interceptors = advisor.getInterceptors();
			if (interceptorMap.containsKey(method)) {
				InterceptorChain chain = interceptorMap.get(method);
				chain.addInterceptors(interceptors);
			} else {
				interceptorMap.put(method, new InterceptorChain(interceptors));
			}
		}
	}
}
